| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- /**
- * First-party Briven Auth proxy (auth-core FDI).
- *
- * Browser → http://localhost:3000/api/auth/…
- * Upstream → https://api.briven.tech/v1/auth-core/fdi/…
- *
- * @briven/auth SDK builds: {apiOrigin}/v1/auth-core/fdi/signinup/code
- * With apiOrigin = same-origin + "/api/auth", full path is:
- * /api/auth/v1/auth-core/fdi/signinup/code
- * We strip a leading v1/auth-core/fdi/ so we never double the prefix.
- */
- import { NextRequest, NextResponse } from "next/server";
- import {
- brivenUpstreamOrigin,
- collectSetCookies,
- rewriteSetCookieForFirstParty,
- } from "@/lib/auth-proxy";
- export const dynamic = "force-dynamic";
- export const runtime = "nodejs";
- function runtimeEnv(name: string): string {
- return (process.env[name] ?? "").trim();
- }
- type RouteCtx = { params: Promise<{ path: string[] }> };
- async function proxy(req: NextRequest, ctx: RouteCtx): Promise<Response> {
- const { path: segments } = await ctx.params;
- let path = (segments ?? []).join("/");
- if (path.includes("..")) {
- return NextResponse.json({ ok: false, error: "invalid auth path" }, { status: 400 });
- }
- // SDK may send full FDI prefix under /api/auth
- path = path.replace(/^v1\/auth-core\/fdi\/?/, "");
- path = path.replace(/^v1\/auth-tenant\/?/, "");
- path = path.replace(/^v1\/auth-core\/session\/me\/?$/, "session/me");
- const incomingUrl = new URL(req.url);
- // session/me lives outside /fdi/* (gold path); get-session is legacy name
- const isSessionMe = path === "session/me" || path === "get-session";
- const target = isSessionMe
- ? `${brivenUpstreamOrigin()}/v1/auth-core/session/me${incomingUrl.search}`
- : `${brivenUpstreamOrigin()}/v1/auth-core/fdi/${path}${incomingUrl.search}`;
- const headers = new Headers();
- const pass = [
- "content-type",
- "cookie",
- "authorization",
- "x-briven-project-id",
- "rid",
- "fdi-version",
- "st-auth-mode",
- "anti-csrf",
- "user-agent",
- "referer",
- "x-forwarded-for",
- "x-real-ip",
- "cf-connecting-ip",
- ] as const;
- for (const name of pass) {
- const v = req.headers.get(name);
- if (v) headers.set(name, v);
- }
- if (!headers.has("authorization")) {
- const pk =
- runtimeEnv("BRIVEN_AUTH_PUBLIC_KEY") ||
- runtimeEnv("NEXT_PUBLIC_BRIVEN_AUTH_KEY");
- if (pk.startsWith("pk_briven_auth_")) {
- headers.set("authorization", `Bearer ${pk}`);
- }
- }
- if (!headers.has("x-briven-project-id")) {
- const project =
- runtimeEnv("BRIVEN_PROJECT_ID") ||
- runtimeEnv("NEXT_PUBLIC_BRIVEN_PROJECT_ID");
- if (project.startsWith("p_")) {
- headers.set("x-briven-project-id", project);
- }
- }
- const clientIp =
- req.headers.get("cf-connecting-ip")?.trim() ||
- req.headers.get("x-real-ip")?.trim() ||
- req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
- "";
- if (clientIp) {
- headers.set("x-briven-client-ip", clientIp);
- if (!headers.has("x-real-ip")) headers.set("x-real-ip", clientIp);
- if (!headers.has("x-forwarded-for")) headers.set("x-forwarded-for", clientIp);
- }
- const origin = req.headers.get("origin") || incomingUrl.origin;
- if (origin) headers.set("origin", origin);
- // Ensure project id on query for engines that read it there
- const targetUrl = new URL(target);
- const project =
- headers.get("x-briven-project-id") ||
- runtimeEnv("NEXT_PUBLIC_BRIVEN_PROJECT_ID");
- if (project && !targetUrl.searchParams.has("briven_project_id")) {
- targetUrl.searchParams.set("briven_project_id", project);
- }
- const method = req.method.toUpperCase();
- const hasBody = method !== "GET" && method !== "HEAD";
- let upstream: Response;
- try {
- upstream = await fetch(targetUrl.toString(), {
- method,
- headers,
- body: hasBody ? await req.arrayBuffer() : undefined,
- redirect: "manual",
- });
- } catch (err) {
- const message = err instanceof Error ? err.message : "upstream unreachable";
- return NextResponse.json(
- {
- ok: false,
- code: "network_error",
- message: `Auth proxy could not reach Briven: ${message}`,
- },
- { status: 502 },
- );
- }
- const outHeaders = new Headers();
- for (const name of [
- "content-type",
- "cache-control",
- "location",
- "x-request-id",
- "x-briven-session-handle",
- ]) {
- const v = upstream.headers.get(name);
- if (v) outHeaders.set(name, v);
- }
- for (const sc of collectSetCookies(upstream.headers)) {
- outHeaders.append("set-cookie", rewriteSetCookieForFirstParty(sc));
- }
- return new Response(upstream.body, {
- status: upstream.status,
- statusText: upstream.statusText,
- headers: outHeaders,
- });
- }
- export const GET = proxy;
- export const POST = proxy;
- export const PUT = proxy;
- export const PATCH = proxy;
- export const DELETE = proxy;
- export const HEAD = proxy;
- export const OPTIONS = proxy;
|